package com.shelpe.services.algorithm.ranking;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.shelpe.services.algorithm.client.SinbadClient;
import com.shelpe.services.algorithm.entity.jpa.Adgroup;
import com.shelpe.services.algorithm.entity.jpa.Tactics;
import com.shelpe.services.algorithm.entity.jpa.WantRank;
import com.shelpe.services.algorithm.entity.mongo.KeywordDevelopmentLog;
import com.shelpe.services.algorithm.entity.mongo.KeywordRankingLog;
import com.shelpe.services.algorithm.repository.jpa.AdgroupRepository;
import com.shelpe.services.algorithm.repository.jpa.TacticsRepository;
import com.shelpe.services.algorithm.repository.jpa.WantRankRepository;
import com.shelpe.services.algorithm.repository.mongo.KeywordRankingLogRepository;
import com.shelpe.services.algorithm.sustain.SustainRule;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class KeywordRankingSustainRule implements SustainRule<KeywordRankingSustainer> {

	@Autowired
	private SinbadClient sinbadClient;
	@Autowired
	private TacticsRepository tacticsRepository;
	@Autowired
	private WantRankRepository wantRankRepository;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private KeywordRankingLogRepository keywordRankingLogRepository;
	
	@Value("${algorithm.allow.ip:221.176.172.86}")
	private String allowedIP;
	
	@Override
	public boolean check(KeywordRankingSustainer entity) {
		Date today = new Date();
		
		boolean between = true;
		Tactics tactics = entity.getTactics();
		if(tactics.getFromTime() != null && tactics.getToTime() != null){
			if(DateUtils.truncatedCompareTo(tactics.getFromTime(), today, Calendar.MINUTE) > 0 || DateUtils.truncatedCompareTo(tactics.getToTime(), today, Calendar.MINUTE) < 0){
				between = false;
			}
		}
		
		boolean inPeriod = false;
		Date expectedTime = DateUtils.addSeconds(tactics.getModifiedTime(), tactics.getCampaignPeriod());
		if(DateUtils.truncatedCompareTo(expectedTime, today, Calendar.SECOND) < 0 ){
			inPeriod = true;
		}
		boolean isDoing = entity.getRank().getDoing() == WantRank.Doing.executable;
		log.debug("{} between: {}", between, entity.getKeyword());
		log.debug("{} inPeriod: {}", inPeriod, entity.getKeyword());
		log.debug("{} doing: {}", entity.getRank().getDoing(), entity.getKeyword());
		boolean next = between && inPeriod && isDoing;
		
		if(!next){
			log.info("need not execute as between {}, in peroid {} or doing {}, go to next: {} - {}", between, inPeriod, isDoing, tactics, entity.getRank());
			tactics.setModifiedTime(new Date());
			tactics.setNextTime(DateUtils.addSeconds(tactics.getModifiedTime(), tactics.getCampaignPeriod()));
			this.tacticsRepository.save(tactics);
		}
		
		return entity.getKeyword() != null && next;
	}

	@Override
	public boolean prepare(KeywordRankingSustainer entity) {
		if(entity.getKeyword().getAdgroupId() != entity.getAdgroupID()){
			Adgroup adgroup = this.adgroupRepository.findOne((long) entity.getKeyword().getAdgroupId());
			if(adgroup == null){
				log.info("need not execute as adgroup not found, go to next: {} - {}", entity.getTactics(), entity.getRank());
				return false;
			}
			entity.setNick(adgroup.getNick());
			entity.setProductID(adgroup.getProductID());
		}
		return true;
	}

	@Override
	public SustainStatus sustain(KeywordRankingSustainer entity) {
		if(entity.getCurrentItem() != null){
			if(entity.getTactics().getDevice() == 0 && entity.getRank().getWantRank() < entity.getCurrentItem().getPcRank()){
				return SustainStatus.pricing;
			}
			
			if(entity.getTactics().getDevice() == 1 && entity.getRank().getWantRank() < entity.getCurrentItem().getMoibleRank()){
				return SustainStatus.pricing;
			}
		}
		return SustainStatus.keep;
	}

	@Override
	public boolean maintain(KeywordRankingSustainer entity,
			SustainStatus status) {
		Tactics tactics = entity.getTactics();
		
		KeywordRankingLog actionLog = new KeywordRankingLog();
		actionLog.setCurrentRank(entity.getCurrentItem());
		actionLog.setKeyword(new KeywordRankingLog.KeywordSnapshot());
		actionLog.getKeyword().setKeywordID(entity.getKeyword().getKeywordId());
		actionLog.getKeyword().setWord(entity.getKeyword().getWord());
		actionLog.getKeyword().setMaxPrice(entity.getKeyword().getMaxPrice());
		actionLog.getKeyword().setMaxMobilePrice(entity.getKeyword().getMaxMobilePrice());
		actionLog.setKeywordID(entity.getKeyword().getKeywordId());
		actionLog.setLogTime(new Date());
		actionLog.setRank(entity.getRank());
		actionLog.setTactics(entity.getTactics());
		actionLog.setUserID(entity.getKeyword().getKeywordId());
		actionLog.setupID(entity.getKeyword().getKeywordId(), actionLog.getLogTime());
		
		if(status == SustainStatus.pricing){
			int nextPrice = 0;
			boolean isMobile = (entity.getTactics().getDevice() == 1);
			if(isMobile){
				nextPrice = entity.getTactics().getPremium().nextPrice(entity.getKeyword().getMaxMobilePrice());
			}else{
				nextPrice = entity.getTactics().getPremium().nextPrice(entity.getKeyword().getMaxPrice());
			}
			if(nextPrice < tactics.getHeighestPrice()){
				log.debug("pricing keyword: {}", entity.getKeyword());
				List<SinbadClient.PricingKeyword> words = new ArrayList<SinbadClient.PricingKeyword>();
				SinbadClient.PricingKeyword word = new SinbadClient.PricingKeyword();
				word.setKeywordID(entity.getKeyword().getKeywordId());
				word.setMatchScope(entity.getKeyword().getMatchscope());
				word.setIsDefaultPrice(0);
				if(isMobile){
					word.setMobileIsDefaultPrice(0);
					word.setMaxMobilePrice(nextPrice);
					actionLog.getKeyword().setNewMobilePrice(nextPrice);
					word.setMaxPrice(entity.getKeyword().getMaxPrice());
					actionLog.getKeyword().setNewMaxPrice(word.getMaxPrice());
				}else{
					word.setMaxPrice(nextPrice);
					actionLog.getKeyword().setNewMaxPrice(nextPrice);
					if(entity.getKeyword().getMobileIsDefaultPrice() != null && entity.getKeyword().getMobileIsDefaultPrice() == 0){
						word.setMobileIsDefaultPrice(0);
						word.setMaxMobilePrice(entity.getKeyword().getMaxMobilePrice());
						actionLog.getKeyword().setNewMobilePrice(word.getMaxMobilePrice());
					}
				}
				words.add(word);
				SinbadClient.ListResponse<SinbadClient.PricingKeyword> ret = this.sinbadClient.pricingKeywords(entity.getTactics().getUserID(), words);
				log.debug("price keywords ret: {}", ret);
				if(ret.getDatas() != null && ret.getDatas().size() > 0){
					if(words.size() != ret.getDatas().size()){
						log.error("some keywords fail to priced: {}", entity.getKeyword());
					}else{
						actionLog.setResult(true);
					}
				}else{
					log.error("no keyword is success to priced: {}", entity.getKeyword());
				}
			}
			
			actionLog.setAction("pricing");
			this.keywordRankingLogRepository.save(actionLog);
			
			nextPrice = entity.getTactics().getPremium().nextPrice(nextPrice);
			if(nextPrice > tactics.getHeighestPrice()){
				entity.getRank().setDoing(WantRank.Doing.overflowed);
			}else if(nextPrice <= 0){
				entity.getRank().setDoing(WantRank.Doing.negative);
			}
			return true;
		}
		return true;
	}

	@Override
	public boolean mark(KeywordRankingSustainer entity) {
		WantRank rank = entity.getRank();
		rank.setUpdatedTime(new Date());
		this.wantRankRepository.save(rank);
		return true;
	}
	
}
